package mobi.zeedev.flyingsaucer.common.WebLinkModule.impl;

import android.content.ContentValues;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import mobi.zeedev.flyingsaucer.common.CredentialsModule.impl.HomeInfo;
import mobi.zeedev.flyingsaucer.common.CredentialsModule.interfaces.ICredentials;
import mobi.zeedev.flyingsaucer.common.CredentialsModule.interfaces.IPreferenceCredentials;
import mobi.zeedev.flyingsaucer.common.DataModule.tree.DatabaseTree;
import mobi.zeedev.flyingsaucer.common.RegexModule.RegexUtil;
import mobi.zeedev.flyingsaucer.common.RegexModule.impl.ParseException;
import mobi.zeedev.flyingsaucer.common.RegexModule.impl.RegexQueries;
import mobi.zeedev.flyingsaucer.common.RegexModule.interfaces.IRegexQueries;
import mobi.zeedev.flyingsaucer.common.WebLinkModule.BadCredentialsException;
import mobi.zeedev.flyingsaucer.common.WebLinkModule.UfoClientException;
import mobi.zeedev.flyingsaucer.common.WebLinkModule.interfaces.UfoClubClient;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.impl.ContinuousBeerWebQuery;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.impl.HttpException;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.impl.Result;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.interfaces.IBeerWebQuery;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.interfaces.IResult;
import org.apache.http.client.entity.UrlEncodedFormEntity;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.Map.Entry;

//import com.google.inject.Provider;

//import com.google.inject.Inject;

//import com.google.inject.Inject;
//import com.google.inject.Provider;
//import com.google.inject.name.Named;

//import com.google.inject.Provider;
//import roboguice.util.Ln;

//import roboguice.util.Ln;

public class UfoClubClientImpl implements UfoClubClient {

    @Inject
    IRegexQueries regexQueries;

    @Inject
    IBeerWebQuery beerWebQuery;

    @Inject
    @Named("autoIPreferenceCredentials")
    Provider<IPreferenceCredentials> preferenceCredentialsProvider;

    boolean isLoggedIn;
    HomeInfo homeInfoCache;
    Integer memberIdCache;
    Date cacheDate;

    @Inject
    public UfoClubClientImpl() {
        super();
        isLoggedIn = false;
        homeInfoCache = null;
        memberIdCache = null;
        cacheDate = null;
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  Ufo Club Functions
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    @Override
    public void login() throws UfoClientException {

        UfoClientException exceptionCache = null;

        for (int i = 0; i < 4;) {

            UfoClientException currentException = null;

            try {

                long timeToWait = 0;
                if (i == 0 || i == 1) {
                    timeToWait = 0;
                } else {
                    timeToWait = (i - 1) * 3000;
                }

                if (timeToWait > 0) {
                    Thread.sleep(timeToWait);
                }

            } catch (InterruptedException e) {
                throw new UfoClientException("Thread failed to sleep.", e);
            }


            try {
                attemptLogin();
            } catch (BadCredentialsException e) {
                currentException = e;
            } catch (IOException e) {
                currentException = new UfoClientException("IOException.", e);
            } catch (HttpException e) {
                currentException = new UfoClientException("HttpException.", e);
            } catch (ParseException e) {
                currentException = new UfoClientException("ParseException.", e);
            }

            if (currentException != null) {
                logout();
            }

            if (isLoggedIn()) {
                i = 4;

            } else {
                if (currentException != null) {
                    exceptionCache = currentException;
                }
                i++;
                if (i >= 4) {
                    throw new UfoClientException("Client failed to login to Ufo Club.", exceptionCache);
                }

            }


        }

    }

    @Override
    public void attemptLogin() throws IOException, HttpException, ParseException, BadCredentialsException {

        UrlEncodedFormEntity loginCredentials = null;
        IResult resultLogin = null;

        final ICredentials credentials = preferenceCredentialsProvider.get().getCredentials();

//        Ln.i("Logging into Ufo Club.");
        if (isLoggedIn) {

            homeInfoCache = getLoginMain();
            memberIdCache = getMemberId();

        } else {
            //not logged in already
            if (credentials.isLoggedIn()) {
                //do we have the ability to directly login?
                beerWebQuery.resetCookies();
                beerWebQuery.injectCookies(credentials.generateCookieInfo());

                homeInfoCache = getLoginMain();
                memberIdCache = getMemberId();

            } else {
                //we don't have the ability to login and we need to generate the token (the e-mail address)
                loginCredentials = beerWebQuery.generatePostParams(credentials.getLoginParams());
                resultLogin = beerWebQuery.getUrlResultHttpPost(RegexQueries.PAGE_MAIN_LOGIN, loginCredentials, null);
//                resultLogin = beerWebQuery.getUrlResultHttpPost(RegexQueries.PAGE_MAIN, loginCredentials, null);

//                System.out.println("main: " + main.getContent().toString());

//                if (!isRedirect(resultLogin)) {
                if (!isTokenRetrievalSuccessful(resultLogin)) {

//                    IResult main = beerWebQuery.getUrlResultHttpGet(RegexQueries.PAGE_MAIN);
//                    IResult main = beerWebQuery.getUrlResultHttpGet(RegexQueries.PAGE_MAIN);

//                    if (detectIncorrectLoginPage(main)) {
                    throw new BadCredentialsException("Login response should be of type redirect.");
//                    }
                }


//                if (isTokenRetrievalSuccessful(resultLogin)) {

                homeInfoCache = getLoginMain();
                memberIdCache = getMemberId();

//                }
            }
        }

        if (!homeInfoCache.hasEmail()) {
            throw new BadCredentialsException("HomeInfo.E_MAIL cannot be empty.");
        }

        if (isNullOrEmpty(memberIdCache) || memberIdCache <= 0) {
            throw new BadCredentialsException("Member Id cannot be empty.");
        }

        isLoggedIn = true;
        cacheDate = Calendar.getInstance().getTime();
        credentials.setMemberId(memberIdCache);
        credentials.setUserName(homeInfoCache.get(HomeInfo.E_MAIL));
        preferenceCredentialsProvider.get().bindToPreferences();

    }

    private Boolean isNullOrEmpty(Object obj) {
        return obj == null || obj.toString().equals("");
    }

    private Boolean loginPagesValid() {
        return homeInfoCache != null && memberIdCache != null && homeInfoCache.hasEmail() && memberIdCache > 0;
    }

    private Boolean isTokenRetrievalSuccessful(IResult resultLogin) {
        if (resultLogin != null && resultLogin.getStatusCode() == ContinuousBeerWebQuery.HTTP_STATUS_REDIRECT) {
            System.out.println("REDIRECT:");
        }
        System.out.println(resultLogin.getContent());
//
//        Ln.d("Content: " + resultLogin.getContent());


        return resultLogin != null && (resultLogin.getStatusCode() == ContinuousBeerWebQuery.HTTP_STATUS_REDIRECT || resultLogin.getStatusCode() == ContinuousBeerWebQuery.HTTP_STATUS_OK);
    }

    //TODO add exception here
    private Boolean isRedirect(IResult result) {
        if (result != null && result.getStatusCode() != null) {
            return result.getStatusCode() == ContinuousBeerWebQuery.HTTP_STATUS_REDIRECT;
        } else {
            return false;
        }
    }

    @Override
    public Boolean isLoggedIn() {
        return isLoggedIn;
    }

    @Override
    public void logout() {
//        Ln.i("Logging out of Ufo Club.");
        beerWebQuery.resetCookies();
        homeInfoCache = null;
        memberIdCache = null;
        cacheDate = null;
        isLoggedIn = false;
    }

    @Override
    public HomeInfo getHomeInfoCache() {
        if (homeInfoCache == null) {
            return new HomeInfo();
        } else {
            return homeInfoCache;
        }
        //TODO else else refresh homeinfocache and update data holders

    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  Data Access Functions
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    //TODO change to return error string
    private Boolean detectIncorrectLoginPage(IResult result) throws ParseException {

        return regexQueries.detectIncorrectLogin(result);

    }

    @Override
    public List<ContentValues> getTastedPage() throws HttpException, IOException, IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException, ParseException {

        Result result = getBeerResults(RegexQueries.PAGE_TASTED);

        List<Map<String, Object>> o = regexQueries.getTastedUntastedPage(result);

        return RegexUtil.induceContentValuesList(o);

    }

    @Override
    public List<ContentValues> getUntastedPage() throws HttpException, IOException, IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException, ParseException {

        Result result = getBeerResults(RegexQueries.PAGE_NOT_TASTED);

        List<Map<String, Object>> o = regexQueries.getTastedUntastedPage(result);

        return RegexUtil.induceContentValuesList(o);
    }

    @Override
    public Integer getMemberId() throws HttpException, IOException, ParseException, BadCredentialsException {
        IResult result = getBeerResults(RegexQueries.PAGE_PROFILE);

        if (detectIncorrectLoginPage(result)) {
            throw new BadCredentialsException();
        }

        return regexQueries.getMemberPage(result);
    }

    @Override
    public HomeInfo getLoginMain() throws HttpException, IOException, ParseException, BadCredentialsException {

//        UrlEncodedFormEntity postParams = beerWebQuery.generatePostParams(credentialsProvider.get().getLoginParams());

//        Result result = beerWebQuery.getUrlResultHttpPost("http://www.beerknurd.com/member.login.php", postParams, null);

        IResult result = beerWebQuery.getUrlResultHttpGet(RegexQueries.PAGE_MAIN);

        if (detectIncorrectLoginPage(result)) {
            throw new BadCredentialsException();
        }


        HomeInfo homeInfo = regexQueries.getLoginMain(result);


        return homeInfo;


    }

    @Override
    public List<Map<String, Object>> getStoresBeersByCategory(String url) throws HttpException, IOException, ParseException {

        Result result = getBeerResults(url);

        List<Map<String, Object>> ret = regexQueries.getStoresBeersByCategory(result);

        return ret;
    }

    @Override
    public Map<String, String> getStoresURLs() throws IOException, HttpException, ParseException {
        Result result = beerWebQuery.getUrlResultHttpGet(RegexQueries.PAGE_LOGIN);

        return regexQueries.getStoresURLs(result);
    }

    @Override
    public DatabaseTree getStoresTree() throws IOException, HttpException, ParseException {

        Result result = beerWebQuery.getUrlResultHttpGet(RegexQueries.PAGE_LOGIN);

        return regexQueries.getStoresTree(result);

    }

    @Override
    public Map<String, Object> getStoresBeersByName(String url) throws IOException, HttpException, ParseException {
        Result result = getBeerResults(url);
        return regexQueries.getStoresBeersByName(result);
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  Utility Functions
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    private Result getBeerResults(String url) throws HttpException, IOException {
        Result r = null;
        r = beerWebQuery.getUrlResultHttpGet(url);
        return r;
    }

    public static final void mergeDatePage(Map<String, Object> ret, List<ContentValues> cvList, String insertMethod) throws HttpException, IOException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        RegexUtil.merge(ret, insertMethod, cvList);
    }

    public static final void mergeStylePage(Map<String, List<String>> ret, List<ContentValues> cvList, String insertMethod) throws HttpException, IOException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Map<String, Object> newMap = new HashMap<String, Object>();

        for (Entry<String, List<String>> entry : ret.entrySet()) {
            for (String beerName : entry.getValue()) {
                newMap.put(beerName, entry.getKey());
            }
        }

        RegexUtil.merge(newMap, insertMethod, cvList);

    }


}

